//: [Previous](@previous)
import Foundation

//: ## 闭包(Closure)
/**
 一个函数 和 它所捕获的变量/常量环境组合起来, 成为闭包
  - 一般指定义在函数内部的函数
  - 一般它捕获的是外层函数的局部变量/常量
 */
typealias Fn = (Int) -> Int //别名,函数类型
func getFn() -> Fn {// 返回Fn这个函数类型的方法
    var num = 0
    func plus(_ i: Int) -> Int {
        num += i
        return num
    }
    
    return plus
} // 返回的plus 和 num 形成了闭包
var fn1 = getFn()
fn1(1) // num = 0 0+1=1
fn1(2) // num = 1 1+2=3
fn1(3) // num = 3 3+3=6
fn1(4) // num = 6 6+4=10
//这里的重点是num并不会因为是局部变量,就在函数调用完之后销毁,而是会在堆空间内一直保留,所以num会一直累加而不是每次调用都是0开始

func getFn1() -> Fn {
    var num = 0
    return {
        num += $0
        return num
    }
}// 这种用闭包表达式作为返回的,闭包表达式也算是函数,所以也组合成了闭包
/**
 可以把闭包想象成一个类的实例对象
   - 内存在堆空间
   - 捕获的局部变量/常量就是对象的成员(存储属性)
   - 组成闭包的函数就是类内部定义的方法
 */
class Closure {
    var num = 0
    func plus(_ i: Int) -> Int {
        num += i
        return num
    }
}
var cs1 = Closure()
cs1.plus(1)// num = 0 0+1=1
cs1.plus(2)// num = 1 1+2=3
cs1.plus(3)// num = 3 3+3=6
cs1.plus(4)// num = 6 6+4=10

//: ## 自动闭包
// 如果第一个数大于0,就返回第一个数,反之第二个
func getFirstPositive(_ v1: Int, _ v2: Int) -> Int {
    return v1 > 0 ? v1 : v2
}// 这种弊端就是v2的代码,不管三目运算符会不会成功运算到v2,v2都会自己预算,浪费资源
getFirstPositive(10, 20) //20
getFirstPositive(-2, 20) //20
getFirstPositive(0, -4)  //0
// v2改成函数类型的参数,可以让v2延迟加载
func getFirstPositive1(_ v1: Int, _ v2: ()->Int) -> Int {
    return v1 > 0 ? v1 : v2()
}
getFirstPositive1(-4) {
    return 20
} // 20

//@autoclosure 自动闭包
func getFirstPositivew2(_ v1: Int, v2: @autoclosure ()->Int) -> Int? {
    return v1 > 0 ? v1 : v2()
}
getFirstPositivew2(-4, v2: 20)
/**
 @autoclosure 会自动将20 封装成闭包 {20}
 @autoclosure 只支持 ()->T 格式的参数,就是空字符串无参 -> 一个类型
 @autoclosure 并非只支持最后一个参数
 空合并运算符 ?? 使用了 @autoclosure 技术
 有@autoclosure 和 无@autoclosure, 构成了函数重载
 */
// 为了避免和期望冲突, 使用了autoclosure的地方最好明确注释清楚: 这个值会被延迟执行



























//: [Next](@next)
